package com.neusoft.mid.msf.gate.repository;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.common.utils.StringUtils;
import com.neusoft.mid.msf.gate.config.DynamicRouteProperties;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.event.RefreshRoutesEvent;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.stereotype.Component;
import org.apache.commons.lang3.StringUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

/**
 * @program: msf
 * @description: 动态路由的Dao
 * @author: fengjd
 * @create: 2022-07-26 19:59
 **/
@Component
@Slf4j
public class NacosRouteDefinitionRepository  implements RouteDefinitionRepository, ApplicationEventPublisherAware {

    private ConfigService configService;

    private DynamicRouteProperties dynamicRouteProperties;

    private ApplicationEventPublisher publisher ;

    private List<RouteDefinition> routeCache = null;

    private  static ExecutorService pool = new ThreadPoolExecutor(0,100,60L, TimeUnit.SECONDS,new SynchronousQueue<Runnable>());

        private Listener listener = new Listener() {

            @Override
            public Executor getExecutor() { return pool;}

            @Override
            public void  receiveConfigInfo(String configInfo) {
                log.info("gateway router config medified:{}",configInfo);
                routeCache = convert(configInfo);
                notifyChanged();
            }

        };

        public NacosRouteDefinitionRepository (DynamicRouteProperties dynamicRouteProperties, ConfigService configService){
            this.dynamicRouteProperties = dynamicRouteProperties;
            this.configService = configService ;

            try {
                configService.addListener( dynamicRouteProperties.getDataId(),dynamicRouteProperties.getGroupId(),listener );
            } catch (NacosException e) {
                log.error("addListener error: " ,e);
            }
            initRouteCache(); // 加载缓存
        }

    /**
     * 触发网关刷新配置信息, 之后gateway才会刷新自己的路由缓存
     */
    public void notifyChanged() {
        this.publisher.publishEvent(new RefreshRoutesEvent(this));
    }

    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        this.publisher = applicationEventPublisher;
    }

    private  List<RouteDefinition> convert(String json) {
        List<RouteDefinition> routeDefinitions = new ArrayList<>();
        if (StringUtils.isNotEmpty(json)) {
            routeDefinitions = JSONArray.parseArray(json, RouteDefinition.class);
        }
        return routeDefinitions;
    }

    private void initRouteCache(){
        this.routeCache = getRoutes();
    }

    private List<RouteDefinition> getRoutes() {
        List<RouteDefinition> routeDefinitions = new ArrayList<>();

        try {
            String routeJSON = configService.getConfig(dynamicRouteProperties.getDataId(), dynamicRouteProperties.getGroupId(), 3000L);
            log.info("load routes config:{}",routeJSON);
            routeDefinitions= convert(routeJSON);
        } catch (NacosException e) {
            log.error("getRoutes error",e);
        }

        return routeDefinitions;
    }

    private void saveRoutes(List<RouteDefinition> routes){
        try {
            boolean result = configService.publishConfig(dynamicRouteProperties.getDataId(), dynamicRouteProperties.getGroupId(), JSON.toJSONString(routes));
            log.info("safeRoutes:{}",result);
        } catch (NacosException e) {
            log.error("saveRoutes error",e);
        }

    }
}
